import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import * as dat from "lil-gui";
import CANNON from "cannon";
import { CannonDebugRenderer } from "./debug"

//构建场景，点击添加力

export function start() {
    THREE.ColorManagement.enabled = false;

    /**
     * Debug
     */
    const gui = new dat.GUI();
    const debugObject = {};

    debugObject.createSphere = () => {
        createSphere(Math.random() * 0.5, {
            x: (Math.random() - 0.5) * 3,
            y: 3,
            z: (Math.random() - 0.5) * 3,
        });
    };

    debugObject.createBox = () => {
        createBox(Math.random(), Math.random(), Math.random(), {
            x: (Math.random() - 0.5) * 3,
            y: 3,
            z: (Math.random() - 0.5) * 3,
        });
    };

    debugObject.reset = () => {
        for (const object of objectsToUpdate) {
            //Remove body
            object.body.removeEventListener("collide", playHitSound);
            world.removeBody(object.body);

            //Remove Mesh
            scene.remove(object.mesh);
        }
    };

    gui.add(debugObject, "createSphere");
    gui.add(debugObject, "createBox");
    gui.add(debugObject, "reset");

    /**
     * Base
     */
    // Canvas
    const canvas = document.getElementById("canvas");

    // Scene
    const scene = new THREE.Scene();

    //Fog
    const fog = new THREE.Fog("#ffffff", 1, 15);
    scene.fog = fog;

    // const hitSound = new Audio("/sounds/hit.mp3");

    const playHitSound = (collision) => {
        const impactStrength = collision.contact.getImpactVelocityAlongNormal();
        // console.log("碰撞", collision);
        if (impactStrength > 1.5) {
            // hitSound.volume = Math.random();
            // hitSound.currentTime = 0;
            // hitSound.play();
        }
    };

    /**
     * Textures
     */
    const textureLoader = new THREE.TextureLoader();
    const cubeTextureLoader = new THREE.CubeTextureLoader();

    const environmentMapTexture = cubeTextureLoader.load([
        "/asset/img/px.png",
        "/asset/img/nx.png",
        "/asset/img/py.png",
        "/asset/img/ny.png",
        "/asset/img/pz.png",
        "/asset/img/nz.png",
    ]);

    /**
     * Physics
     */
    const world = new CANNON.World();
    world.broadphase = new CANNON.SAPBroadphase(world);
    world.allowSleep = true;
    world.gravity.set(0, -9.92, 0);

    //Materials
    const defaultMaterial = new CANNON.Material("default");

    const defaultContactMaterial = new CANNON.ContactMaterial(
        defaultMaterial,
        defaultMaterial,
        {
            friction: 0.1,
            restitution: 0.7,
        }
    );

    world.addContactMaterial(defaultContactMaterial);
    world.defaultContactMaterial = defaultContactMaterial;

    world.solver.iterations = 30;
    console.log("world", world)

    //Floor
    const floorShape = new CANNON.Plane();
    const floorBody = new CANNON.Body();
    floorBody.mass = 0;
    floorBody.addShape(floorShape);
    floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(-1, 0, 0), Math.PI * 0.5);
    world.addBody(floorBody);

    /**
     * Floor
     */
    const floor = new THREE.Mesh(
        new THREE.PlaneGeometry(30, 30),
        new THREE.MeshStandardMaterial({
            color: "#fefefe",
            // side: THREE.DoubleSide,
            metalness: 0.3,
            roughness: 0.4,
            envMap: environmentMapTexture,
            envMapIntensity: 0.5,
        })
    );
    floor.receiveShadow = true;
    floor.rotation.x = -Math.PI * 0.5;
    scene.add(floor);

    /**
     * Lights
     */
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.1);
    directionalLight.castShadow = true;
    directionalLight.shadow.mapSize.set(1024, 1024);
    directionalLight.shadow.camera.far = 15;
    directionalLight.shadow.camera.left = -7;
    directionalLight.shadow.camera.top = 7;
    directionalLight.shadow.camera.right = 7;
    directionalLight.shadow.camera.bottom = -7;
    directionalLight.position.set(5, 10, 5);
    scene.add(directionalLight);

    /**
     * Sizes
     */
    const sizes = {
        width: window.innerWidth,
        height: window.innerHeight,
    };

    window.addEventListener("resize", () => {
        // Update sizes
        sizes.width = window.innerWidth;
        sizes.height = window.innerHeight;

        // Update camera
        camera.aspect = sizes.width / sizes.height;
        camera.updateProjectionMatrix();

        // Update renderer
        renderer.setSize(sizes.width, sizes.height);
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    });

    /**
     * Camera
     */
    // Base camera
    const camera = new THREE.PerspectiveCamera(
        75,
        sizes.width / sizes.height,
        0.1,
        100
    );
    camera.position.set(-3, 3, 3);
    scene.add(camera);

    var cannonDebugRenderer = new CannonDebugRenderer(scene, world);

    // Controls
    const controls = new OrbitControls(camera, canvas);
    // controls.enableZoom = false;
    controls.enableDamping = true;

    /**
     * Renderer
     */
    const renderer = new THREE.WebGLRenderer({
        canvas: canvas,
    });
    renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.setSize(sizes.width, sizes.height);
    renderer.setClearColor(0xffffff);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

    /**
     * Utils
     */
    const objectsToUpdate = [];

    //Sphere
    const sphereGeometry = new THREE.SphereGeometry(1, 20, 20);
    const sphereMaterial = new THREE.MeshStandardMaterial({
        metalness: 0.3,
        roughness: 0.4,
        envMap: environmentMapTexture,
    });
    const createSphere = (radius, position) => {
        const mesh = new THREE.Mesh(sphereGeometry, sphereMaterial);
        mesh.scale.set(radius, radius, radius);
        mesh.castShadow = true;
        mesh.position.copy(position);
        scene.add(mesh);

        //Cannon
        const shape = new CANNON.Sphere(radius);
        const body = new CANNON.Body({
            mass: 1,
            position: new CANNON.Vec3(0, 4, 0),
            shape: shape,
            material: defaultMaterial,
        });
        body.position.copy(position);
        body.addEventListener("collide", playHitSound);
        world.addBody(body);

        body.allowSleep = false

        mesh.userData.body = body;

        objectsToUpdate.push({
            mesh,
            body,
        });
    };

    createSphere(0.5, { x: 0, y: 3, z: 0 });

    //Box
    const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
    const boxMaterial = new THREE.MeshStandardMaterial({
        metalness: 0.3,
        roughness: 0.4,
        envMap: environmentMapTexture,
    });
    const createBox = (width, height, depth, position, mass = 1) => {
        const mesh = new THREE.Mesh(boxGeometry, boxMaterial);
        mesh.scale.set(width, height, depth);
        mesh.castShadow = true;
        mesh.position.copy(position);
        scene.add(mesh);

        //Cannon
        const shape = new CANNON.Box(
            new CANNON.Vec3(width * 0.5, height * 0.5, depth * 0.5)
        );
        const body = new CANNON.Body({
            mass,
            position: new CANNON.Vec3(0, 4, 0),
            shape: shape,
            material: defaultMaterial,
        });
        body.position.copy(position);
        body.addEventListener("collide", playHitSound);
        world.addBody(body);
        body.allowSleep = false

        mesh.userData.body = body;

        objectsToUpdate.push({
            mesh,
            body,
        });

        return body;
    };

    setView();
    function setView() {
        scene.add(new THREE.AxesHelper(2))
        // createBox(1, 2, 0.2, { x: 0, y: 1, z: -2 }, 0);
        // createBox(1, 2, 0.2, { x: 0, y: 1, z: 2 }, 0);

        const quaternion = new CANNON.Quaternion();
        quaternion.setFromAxisAngle(new CANNON.Vec3(0, 1, 0), Math.PI / 2); // 绕 y 轴旋转 90 度
        let r = 1;
        let body1 = createBox(1, 2, 0.2, { x: -r, y: 1, z: 0 }, 0);
        body1.quaternion.copy(quaternion);

        let body2 = createBox(1, 2, 0.2, { x: r, y: 1, z: 0 }, 0);
        body2.quaternion.copy(quaternion);

        createBox(1, 2, 0.2, { x: 0, y: 1, z: -r }, 0);
        createBox(1, 2, 0.2, { x: 0, y: 1, z: r }, 0);

    }

    window.addEventListener("click", handleClick)

    function handleClick(event) {
        // 获取点击位置的屏幕坐标
        const mouse = new THREE.Vector2();
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

        // 通过射线投射获取点击位置的物体
        const raycaster = new THREE.Raycaster();
        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObjects(scene.children, true);

        if (intersects.length > 0) {
            const worldPosition = intersects[0].point;
            console.log("点击位置的世界坐标:", worldPosition);
            for (let i = 0; i < intersects.length; i++) {
                const obj = intersects[0].object;
                for (const object of objectsToUpdate) {
                    if (object.mesh == obj) {
                        object.mesh.userData.body.allowSleep = false;
                        // 给刚体施加沿 Y 轴方向的力
                        const force = new CANNON.Vec3(10, 120, -20);
                        const p = new CANNON.Vec3(worldPosition.x, worldPosition.y, worldPosition.z);
                        console.log(p)
                        object.mesh.userData.body.applyForce(force, p);
                        console.log("点击", object.mesh)
                        return
                    }
                }
            }

        }

    }

    /**
     * Animate
     */
    const clock = new THREE.Clock();
    let oldElapsedTime = 0;

    const tick = () => {
        const elapsedTime = clock.getElapsedTime();
        const deltaTime = elapsedTime - oldElapsedTime;
        oldElapsedTime = elapsedTime;

        //Update Physics World
        world.step(1 / 60, deltaTime, 3);

        for (const object of objectsToUpdate) {
            object.mesh.position.copy(object.mesh.userData.body.position);
            object.mesh.quaternion.copy(object.mesh.userData.body.quaternion);
        }

        cannonDebugRenderer.update();

        // Update controls
        // controls.update();

        // Render
        renderer.render(scene, camera);

        // Call tick again on the next frame
        window.requestAnimationFrame(tick);
    };

    tick();
}